﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Text;
using Sector7.Restaurant.EntityType;
using Sector7.Restaurant.DAO.OleDB;
using Sector7.Restaurant.DAO;
using Sector7.Restaurant.Contracts;
using Sector7.Restaurant.DAO.Utility;
using Sector7.Framework.Enums;

namespace Sector7.Restaurant.Services
{
    // 注意: 使用“重构”菜单上的“重命名”命令，可以同时更改代码和配置文件中的类名“LocalService”。
    public class LocalService : LocalContract
    {
        private IUnitDAO _unitDAO = new UnitDAO();

        private IMetadataDAO _metadataDAO = new MetadataDAO();
        private IMetadataTypeDAO _metadataTypeDAO = new MetadataTypeDAO();

        private IEmployeeDAO _employeeDAO = new EmployeeDAO();
        private IEmployeeGroupDAO _employeeGroupDAO = new EmployeeGroupDAO();

        private IRoomDAO _roomDAO = new RoomDAO();
        private ITableDAO _tableDAO = new TableDAO();

        private IMenuItemTypeDAO _menuItemTypeDAO = new MenuItemTypeDAO();
        private IMenuItemLabelDAO _menuItemLabelDAO = new MenuItemLabelDAO();
        private IMenuItemDAO _menuItemDAO = new MenuItemDAO();
        
        private ISalesBillDAO _salesBillDAO = new SalesBillDAO();
        private ISalesBillItemDAO _salesBillItemDAO = new SalesBillItemDAO();

        private IPurchaseBillDAO _purchaseBillDAO = new PurchaseBillDAO();
        private IPurchaseBillItemDAO _purchaseBillItemDAO = new PurchaseBillItemDAO();

        private IChargeDAO _chargeDAO = new ChargeDAO();

        private ICompanyDAO _companyDAO = new CompanyDAO();

        /***************************************************************************************/

        public RS_Employee LoginSystem(string userName, string password)
        {
            return _employeeDAO.Read(userName, password);
        }

        public int AddUnit(RS_Unit unit)
        {
            return _unitDAO.Create(unit);
        }

        public List<RS_Unit> GetAllUnits()
        {
            return _unitDAO.ReadAll();
        }

        public int SetUnit(EntityDelta delta)
        {
            return _unitDAO.Update(delta);
        }

        public int AddMetadata(RS_Metadata metadata)
        {
            return _metadataDAO.Create(metadata);
        }

        public int SetMetadata(EntityDelta delta)
        {
            return _metadataDAO.Update(delta);
        }

        public List<RS_Metadata> GetAllMetadatasForUsage(int usage)
        {
            return _metadataDAO.ReadAllForUsage(usage);
        }

        public int AddMetadataType(RS_MetadataType type)
        {
            return _metadataTypeDAO.Create(type);
        }

        public List<RS_MetadataType> GetAllMetadataTypes(bool isGreedy)
        {
            return _metadataTypeDAO.ReadAll(isGreedy);
        }

        public List<RS_MetadataType> GetAllMetadataTypesForUsage(int usage, bool isGreedy)
        {
            return _metadataTypeDAO.ReadAll(usage, isGreedy);
        }

        public int SetMetadataType(EntityDelta delta)
        {
            return _metadataTypeDAO.Update(delta);
        }

        public long AddEmployee(RS_Employee employee)
        {
            return _employeeDAO.Create(employee);
        }

        public int SetEmployee(EntityDelta employeeDelta)
        {
            return _employeeDAO.Update(employeeDelta);
        }

        public int AddEmployeeGroup(RS_EmployeeGroup group)
        {
            return _employeeGroupDAO.Create(group);
        }

        public List<RS_EmployeeGroup> GetAllEmployeeGroups(bool isGreedy)
        {
            return _employeeGroupDAO.ReadAll(isGreedy);
        }

        public int SetEmployeeGroup(EntityDelta delta)
        {
            return _employeeGroupDAO.Update(delta);
        }

        public int AddRoom(RS_Room room)
        {
            return _roomDAO.Create(room);
        }

        public List<RS_Room> GetAllRooms(bool isGreedy)
        {
            return _roomDAO.ReadAll(isGreedy);
        }

        public int SetRoom(EntityDelta delta)
        {
            return _roomDAO.Update(delta);
        }

        public int AddTable(RS_Table table)
        {
            return _tableDAO.Create(table);
        }

        public List<RS_Table> GetAllTables()
        {
            return _tableDAO.ReadAll();
        }

        public int SetTable(EntityDelta delta)
        {
            return _tableDAO.Update(delta);
        }

        public List<RS_MenuItemType> GetAllMenuItemTypes(bool isGreedy)
        {
            return _menuItemTypeDAO.ReadAll(isGreedy);
        }

        public int AddMenuItemLabel(RS_MenuItemLabel label)
        {
            return _menuItemLabelDAO.Create(label);
        }

        public List<RS_MenuItemLabel> GetAllMenuItemLabels()
        {
            return _menuItemLabelDAO.ReadAll();
        }

        public int SetMenuItemLabel(EntityDelta delta)
        {
            return _menuItemLabelDAO.Update(delta);
        }

        public string AddMenuItem(RS_MenuItem menuItem)
        {
            string pk = null;

            menuItem.MenuItemId = PrimaryKeyUtil.Generate(typeof(RS_MenuItem), menuItem.MetadataTypeId, menuItem.MetadataId, menuItem.UnitId).ToString();             

            int result = _menuItemDAO.Create(menuItem);

            if (result == 1)
            {
                pk = menuItem.MenuItemId;
            }

            return pk;
        }

        public int SetMenuItem(EntityDelta delta)
        {
            return _menuItemDAO.Update(delta);
        }

        public RS_MenuItem GetMenuItem(string menuItemId)
        {
            return _menuItemDAO.Read(menuItemId);
        }

        public string AddSalesBill(RS_SalesBill bill)
        {
            // 1. Generate PK
            bill.BillId = PrimaryKeyUtil.Generate(typeof(RS_SalesBill)).ToString();
            bill.Items.ForEach(delegate(RS_SalesBillItem billItem)
            {
                billItem.BillId = bill.BillId;
            });

            // 2. Insert SalesBill
            _salesBillDAO.Create(bill);

            // 3. Insert SalesBillItem
            _salesBillItemDAO.Create(bill.Items);
            
            // 4. Update Table's status
            EntityDelta tableDelta = new EntityDelta();

            tableDelta.EntityName = "RS_Table";
            tableDelta.Conditions = new Dictionary<string, object>();
            tableDelta.DeltaProperties = new Dictionary<string, object>();
            tableDelta.Conditions.Add("TableId", bill.TableId);
            tableDelta.DeltaProperties.Add("Status", 2);

            _tableDAO.Update(tableDelta);

            // 5. Return SalesBill's id
            return bill.BillId;
        }

        public string AddPurchaseBill(RS_PurchaseBill bill)
        {
            // 1. Generate PK
            string chargeId = PrimaryKeyUtil.Generate(typeof(RS_Charge), (int)ChargeType.Expenditures).ToString();

            bill.BillId = PrimaryKeyUtil.Generate(typeof(RS_PurchaseBill)).ToString();
            bill.Items.ForEach(delegate(RS_PurchaseBillItem billItem)
            {
                billItem.BillId = bill.BillId;
            });

            // 2. Insert PurchaseBill
            _purchaseBillDAO.Create(bill);

            // 3. Insert PurchaseBillItem
            _purchaseBillItemDAO.Create(bill.Items);

            // 4. Insert Charge
            RS_Charge charge = new RS_Charge();
            charge.ChargeId = chargeId;
            charge.ChargeItem = (int)ChargeItemType.Purchases;      // 1 - Sales; 2 - Purchase
            charge.ChargeType = (int)ChargeType.Expenditures;    // 1 - Revenues; 2 - Expenditure
            charge.BillId = bill.BillId;
            charge.Amount = bill.Amount;
            charge.OccurTime = DateTime.Now;
            charge.Remarks = string.Empty;

            _chargeDAO.Create(charge);

            // 5. Update Stock

            return bill.BillId;
        }

        public RS_SalesBill GetSalesBillForTable(int tableId)
        {
            return _salesBillDAO.Read(tableId);
        }

        public int SetSalesBill(EntityDelta delta)
        {
            if (delta.DeltaProperties.Keys.Contains("Status") &&
               (BillStatusType)delta.DeltaProperties["Status"] == BillStatusType.Done)
            {
                // 1. Generate PK
                string chargeId = PrimaryKeyUtil.Generate(typeof(RS_Charge), (int)ChargeType.Revenues).ToString();

                // 2. Insert Charge
                RS_Charge charge = new RS_Charge();
                charge.ChargeId = chargeId;
                charge.ChargeItem = (int)ChargeItemType.Sales;  // 1 - Sales; 2 - Purchase
                charge.ChargeType = (int)ChargeType.Revenues;   // 1 - Revenues; 2 - Expenditure
                charge.BillId = delta.Conditions["BillId"].ToString();
                charge.Amount = Convert.ToDecimal(delta.DeltaProperties["Amount"]);
                charge.OccurTime = DateTime.Now;
                charge.Remarks = string.Empty;

                _chargeDAO.Create(charge);

                // 3. Update SalesBill's status
                delta.DeltaProperties["Status"] = BillStatusType.Done;
                _salesBillDAO.Update(delta);

                // 4. Update Table's status
                EntityDelta tableDelta = new EntityDelta();
                
                tableDelta.EntityName = "RS_Table";
                tableDelta.Conditions = new Dictionary<string, object>();
                tableDelta.DeltaProperties = new Dictionary<string, object>();
                tableDelta.Conditions.Add("TableId", delta.DeltaProperties["TableId"]);
                tableDelta.DeltaProperties.Add("Status", (int)TableStatusType.Idle);

                _tableDAO.Update(tableDelta);
            }
            else
            {
                _salesBillDAO.Update(delta);
            }

            return 1;
        }

        public int AddCharge(RS_Charge charge)
        {
            throw new NotImplementedException();
        }

        public List<RS_Charge> GetAllChargesForRange(DateTime begin, DateTime end)
        {
            return _chargeDAO.ReadAll(begin, end);
        }

        public int AddCompany(S7_Company company)
        {
            return Convert.ToInt32(_companyDAO.Create(company));
        }

        public S7_Company GetCompany(string uniqueId)
        {
            return _companyDAO.Read(uniqueId);
        }

        public int SetCompany(EntityDelta delta)
        {
            return _companyDAO.Update(delta);
        }
    }
}
